package com.google.android.location.content;


import static com.google.android.location.content.Constants.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.location.Location;
import android.util.Log;

import com.google.android.location.content.libcontent.Route;
import com.google.android.location.content.libcontent.RouteLocation;
import com.google.android.location.content.libdata.CreateLocationFactory;
import com.google.android.location.content.libdata.MyRouteProvider;
import com.google.android.location.content.libdata.MyRouteProvider.LocationIterator;

public class MyRouteCalculator 
{
	MyRouteProvider providerUtils;
	CreateLocationFactory locationFactory;
	Context context;
	Route currentRoute;
	List<List<Node>> paths = new LinkedList<List<Node>>();
	Map<Node, List<Node>> graph = new HashMap<Node, List<Node>>();
	Location startLocation;
	double totalProbability = 0;
    public MyRouteCalculator(MyRouteProvider providerUtils,CreateLocationFactory locationFactory, 
    		                 Context context, Route currentRoute)
    {
    	
    	this.context = context;
    	this.providerUtils = providerUtils;
    	this.locationFactory = locationFactory;
    	this.currentRoute = currentRoute;
    }
	public void setLocation(RouteLocation locationToInsert) 
	{
		this.startLocation = locationToInsert;	
	}
	public boolean computeGraph() 
	{
	   //startLocation = tocheck;
	   List<Route>routes = providerUtils.getAllRoutes();
	   for(Route route : routes)
	   {
		   try 
		   {
			   LocationIterator it = providerUtils.getLocationIterator(route.getId(), route.getStart_id(), true, locationFactory);
			   Node prevLocationNode= null;
			   while(it.hasNext())
			   {
				  
				   Node newNode=null;
				   Location loc = it.next();
				   if(loc.equals(route.getLocations().get(0)))
				   {
					   prevLocationNode = new Node(loc,0);
				   }
				   
				   else
				   {
					   newNode = new Node(loc,0);
					   
					   List<Node>adjacencyList;
					   if(graph.containsKey(prevLocationNode))
					   {
						   adjacencyList = graph.get(prevLocationNode);
					   }
					   else
					   {
						   adjacencyList = new LinkedList<Node>();
					   }
					   
					   if(!adjacencyList.contains(newNode))
					   {
						   adjacencyList.add(newNode);
						   graph.put(newNode, adjacencyList);
					   }
				   }
				   prevLocationNode = newNode;
			   }
			   it.close();
		   } 
		   catch (Exception e) 
		   {
		       Log.w(TAG, "Iterator error return false");
		       return false;
		   }  
	   }
	   return true;
	}
	boolean routeSearch(Map<Node, List<Node>>  graph, Node currentNode, 
			         Node destination, List<Node> currentPath)
	{
		if(currentNode == destination)
		{
			//print the route eventually
			paths.add(currentPath);
		}
		;
		for(Node node : graph.get(currentNode))
		{
			if(node.getColor()==2)
			{
				return false;
			}
			//currentPath.add(currentNode)
			else if(node.getColor()==1)
			{
				node.setColor(2);
			}
			else if(node.getColor()==0)
			{
				node.setColor(1);
			}
			currentPath.add(currentNode);
			routeSearch(graph, node, destination, currentPath);
		}
		return true;
	}
	public double probCheck(Location tocheck)
	{
		if(computeGraph())
		{
			List<Node>currentPath = new ArrayList<Node>();
			Node currentNode = new Node(startLocation, 0);
			Node destination = new Node(tocheck,0);
			if(routeSearch(graph, currentNode, destination, currentPath))
			{
				if(!paths.isEmpty())
				{
					return calcProbability();	
				}	   
			}	
		}
		return 1;
	
	}
	public double calcProbability()
	{
		double localProb = 1;
		for(List<Node>path : paths)
		{
			Node prevNode=null;
			boolean first = true;
			for(Node node : path)
			{
				if(first)
				{
					first = false;
					prevNode = node;
				}
				else
				{
					if(prevNode==null)
					{
						Log.d(TAG, "MyRouteCalc:shouldn't go here");
						return 1;
					}
					int concurents =  graph.get(prevNode).size();
					double probEdge = 1/concurents;
					localProb *=probEdge;
					prevNode = node;
				}
			}
			totalProbability +=localProb;
		}
		return totalProbability;
	}
	class Node
	{
		Location location;
		int color;
		public Node(Location loc, int color)
		{
			this.location = loc;
			this.color = color;
		}
		public Location getLocation()
		{
			return location;
		}
		public void setLocation(Location loc)
		{
			this.location = loc;
		}
		public void setColor(int color)
		{
			this.color = color;
		}
		public int getColor()
		{
			return color;
		}
	}
}
